import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.LineBorder;


public class GUI extends JFrame{
	HRASystem hras;
	
	JButton newEmployeeBtn, newDepartmentBtn, editEmployeeBtn, deleteEmployeeBtn, 
	deleteDepartmentBtn, assignHeadBtn, unassignHeadBtn, generatePayrollBtn;
	JComboBox departmentsBox, employeesBox, assignDepartmentBox, assignEmployeeBox, dataDepartmentBox;
	JTextArea employeeDataTa;
	
	ButtonHandler buttonHandler = new ButtonHandler();
	ComboBoxHandler comboBoxHandler = new ComboBoxHandler();
	
	ArrayList<Department> departments;
	Map<Integer, Employee> employees;
	
	
	public static void main(String args[]){
		final GUI gui = new GUI();
		gui.setVisible(true);
		gui.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent event) {
				//When user closes the frame, all data from departments and employees is saved to the binaryfile
				HRASystem h = gui.getHras();
				try {
					JOptionPane.showMessageDialog(gui, "The system is saving all data before closing !");
					h.departments_file.saveData(h.getAllDepartments());     //departments data saved to departments.txt
					h.employees_file.saveData(h.getEmployeesList());	    //employees data saved to employees.txt
					System.exit(0);
				} catch (Exception ex) {
					JOptionPane.showMessageDialog(gui, "System failed to save your data !!!");
					ex.printStackTrace();
				}
			}
		});
	}
	
	public GUI(){
		super("Human Resource Administration System");
		setSize(570, 447);
		getContentPane().setLayout(null);
		setResizable(false);
		
		//Initialising the system and get employees and departments data
		try {
			hras = new HRASystem();
			departments = hras.getAllDepartments();
			employees   = hras.getAllEmployees();
			
			//Create 3 panels
			getContentPane().add(createEmployeePanel());
			getContentPane().add(createDepartmentPanel());
			getContentPane().add(createAssignHeadPanel());
			getContentPane().add(createDataPanel());
			
		} catch(SystemException ex){
			JOptionPane.showMessageDialog(getContentPane(), ex.getMessage());
			System.exit(0);
		} catch(FileNotFoundException ex){
			JOptionPane.showMessageDialog(getContentPane(), "startup.txt not found !");
			System.exit(0);
		} catch(IOException ex){
			JOptionPane.showMessageDialog(getContentPane(), "System encountered an I/O problem !");
			System.exit(0);
		} catch (Exception e) {
			JOptionPane.showMessageDialog(getContentPane(), "Fatal error. System can't load !!!");
			e.printStackTrace();
			System.exit(0);
		}
	}
	
	public HRASystem getHras(){
		return hras;
	}
	
	public JPanel createEmployeePanel(){
		
		JPanel panel = new JPanel();
		panel.setBorder(new LineBorder(Color.LIGHT_GRAY));
		panel.setBounds(0, 0, 266, 118);
		getContentPane().add(panel);
		panel.setLayout(null);
		
		JLabel employeeLbl = new JLabel("Employee Panel");
		employeeLbl.setBounds(16, 6, 106, 16);
		panel.add(employeeLbl);
		
		employeesBox = new JComboBox();
		for(Integer i : employees.keySet()){
			employeesBox.addItem(employees.get(i));
		}
		employeesBox.setBounds(6, 34, 228, 27);
		panel.add(employeesBox);
		
		newEmployeeBtn = new JButton("New");

		newEmployeeBtn.setBounds(6, 64, 75, 29);
		panel.add(newEmployeeBtn);
		
		editEmployeeBtn = new JButton("Edit");
		editEmployeeBtn.setBounds(81, 64, 75, 29);
		panel.add(editEmployeeBtn);
		
		deleteEmployeeBtn = new JButton("Delete");
		deleteEmployeeBtn.setBounds(150, 64, 84, 29);
		panel.add(deleteEmployeeBtn);
		
		newEmployeeBtn.addActionListener(buttonHandler);
		editEmployeeBtn.addActionListener(buttonHandler);
		deleteEmployeeBtn.addActionListener(buttonHandler);

		
		return panel;
	}
	
	public JPanel createDepartmentPanel(){
		JPanel departmentPanel = new JPanel();
		departmentPanel.setBorder(new LineBorder(Color.LIGHT_GRAY));
		departmentPanel.setBounds(0, 117, 266, 159);
		getContentPane().add(departmentPanel);
		departmentPanel.setLayout(null);
		
		JLabel departmentLbl = new JLabel("Department Panel");
		departmentLbl.setBounds(16, 6, 120, 16);
		departmentPanel.add(departmentLbl);
		
		departmentsBox = new JComboBox();
		for(Department d : departments){
			departmentsBox.addItem(d);
		}
		departmentsBox.setBounds(6, 28, 227, 27);
		departmentPanel.add(departmentsBox);
		
		newDepartmentBtn = new JButton("New");
		newDepartmentBtn.setBounds(6, 59, 109, 29);
		departmentPanel.add(newDepartmentBtn);
		
		deleteDepartmentBtn = new JButton("Delete");
		deleteDepartmentBtn.setBounds(124, 59, 109, 29);
		departmentPanel.add(deleteDepartmentBtn);
		
		generatePayrollBtn = new JButton("Generate Payroll");
		generatePayrollBtn.setBounds(6, 89, 227, 29);
		departmentPanel.add(generatePayrollBtn);
		
		
		newDepartmentBtn.addActionListener(buttonHandler);
		deleteDepartmentBtn.addActionListener(buttonHandler);
		generatePayrollBtn.addActionListener(buttonHandler);


		return departmentPanel;
	}
	
	public JPanel createAssignHeadPanel(){
		
		JPanel assignPanel = new JPanel();
		assignPanel.setBorder(new LineBorder(Color.LIGHT_GRAY));
		assignPanel.setBounds(0, 275, 266, 150);
		getContentPane().add(assignPanel);
		assignPanel.setLayout(null);
		
		JLabel lblNewLabel = new JLabel("Assign head");
		lblNewLabel.setBounds(16, 9, 101, 16);
		assignPanel.add(lblNewLabel);
		
		assignDepartmentBox = new JComboBox();
		assignDepartmentBox.addItemListener(comboBoxHandler);
		assignEmployeeBox   = new JComboBox();
		for(Department d : departments){
			assignDepartmentBox.addItem(d);
		}
		
		
		assignDepartmentBox.setBounds(6, 37, 227, 27);
		assignPanel.add(assignDepartmentBox);
		
		assignEmployeeBox.setBounds(6, 76, 227, 27);
		assignPanel.add(assignEmployeeBox);
		
		assignHeadBtn = new JButton("Assign");
		unassignHeadBtn = new JButton("Unassign");
		assignHeadBtn.addActionListener(buttonHandler);
		unassignHeadBtn.addActionListener(buttonHandler);
		assignHeadBtn.setBounds(16, 115, 100, 29);
		unassignHeadBtn.setBounds(133, 115, 100, 29);
		assignPanel.add(assignHeadBtn);
		assignPanel.add(unassignHeadBtn);
		
		return assignPanel;
	}
	
	public JPanel createDataPanel(){
		JPanel dataPanel = new JPanel();
		dataPanel.setBorder(new LineBorder(Color.LIGHT_GRAY));
		dataPanel.setBounds(265, 0, 311, 425);
		getContentPane().add(dataPanel);
		dataPanel.setLayout(null);
		
		dataDepartmentBox = new JComboBox();
		dataDepartmentBox.addItemListener(comboBoxHandler);
		employeeDataTa = new JTextArea();
		for(Department d : departments){
			dataDepartmentBox.addItem(d);
		}
		dataDepartmentBox.setBounds(16, 35, 278, 27);
		dataPanel.add(dataDepartmentBox);
		
		JLabel lblEmployeeData = new JLabel("Employee data");
		lblEmployeeData.setBounds(16, 6, 103, 16);
		dataPanel.add(lblEmployeeData);
		
		JScrollPane areaScrollPane = new JScrollPane(employeeDataTa);
		areaScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		areaScrollPane.setBounds(17, 85, 277, 321);
		employeeDataTa.setEditable(false);
		dataPanel.add(areaScrollPane);
		
		return dataPanel;
	}
	
	private class ButtonHandler implements ActionListener{
		@Override
		public void actionPerformed(ActionEvent event) {
			Object o = event.getSource();
			if(o == newEmployeeBtn){
				//Popup a new frame to add a new Employee
				EmployeeFrame employeeFrame = new EmployeeFrame(0); // 0 - mode new
				employeeFrame.setVisible(true);
			}
			else if(o == editEmployeeBtn){
				//Popup a new frame to edit a selected Employee
				EmployeeFrame employeeFrame = new EmployeeFrame(1); // 1 - edit mode
				employeeFrame.setVisible(true);
			}
			else if(o == deleteEmployeeBtn){
				Employee e = (Employee) employeesBox.getSelectedItem();   //Get employee from combobox
				hras.deleteEmployee(e);								      //Delete from hras
				employees   = hras.getAllEmployees();                     //Get Employee Map again after deleting one
				departments = hras.getAllDepartments();
				//Refresh employee combobox
				employeesBox.removeAllItems();
				for(Integer i : employees.keySet()){
					employeesBox.addItem(employees.get(i));
				}
				JOptionPane.showMessageDialog(getContentPane(), "Deleted employee: "+e);
				
			}
			else if(o == newDepartmentBtn){
				//Popup a new frame to add a new Department
				DepartmentFrame departmentFrame = new DepartmentFrame();
				departmentFrame.setVisible(true);
			}
			else if(o == deleteDepartmentBtn){
				Department de = (Department) departmentsBox.getSelectedItem();
				//If it is able to delete the department
				try {
					hras.deleteDepartment(de);
					JOptionPane.showMessageDialog(getContentPane(), "Deleted department: "+de);
					//Refresh department combobox
					departmentsBox.removeAllItems();
					for(Department d : departments){
						departmentsBox.addItem(d);
					}
				} catch (SystemException e) {
					JOptionPane.showMessageDialog(getContentPane(), e.getMessage());
				}
			}
			else if(o == assignHeadBtn){
				//Get employee from combobox and assign to selected department
				Department de = (Department) assignDepartmentBox.getSelectedItem();
				Employee em   = (Employee)   assignEmployeeBox.getSelectedItem();
				try {
					hras.assignHeadToDepartment(de, em);
					JOptionPane.showMessageDialog(getContentPane(), "Assigned new head of "+de);
				} catch (SystemException e) {
					JOptionPane.showMessageDialog(getContentPane(), e.getMessage() + de.getHead() + " is the current head");
				}
			}
			else if(o == unassignHeadBtn){
				//Get employee from combobox and assign to selected department
				Department de = (Department) assignDepartmentBox.getSelectedItem();
				hras.unassignHeadFromDepartment(de);
				JOptionPane.showMessageDialog(getContentPane(), "Unassigned the head of "+de);
			}
			else if(o == generatePayrollBtn){
				try {
					//Generate payroll and save it in payroll.txt
					hras.payroll.saveData(hras.getAllDepartments());
					JOptionPane.showMessageDialog(getContentPane(), "Payroll has been generated!");
				} catch (Exception ex) {
					JOptionPane.showMessageDialog(getContentPane(), "There was a problem generating a payroll!");
					ex.printStackTrace();
				}
			}
		}
	}
	
	private class ComboBoxHandler implements ItemListener{
		@Override
		public void itemStateChanged(ItemEvent event) {
			if(event.getSource() == assignDepartmentBox){
				//When a certain department is selected from combobox, 
				//show only employees from that department in the other combobox
				Department d = (Department) event.getItem();
				//Refresh employess from certain department combobox
				assignEmployeeBox.removeAllItems();
				for(Employee e : d.getEmployees()){
					assignEmployeeBox.addItem(e);
				}
			}
			else if(event.getSource() == dataDepartmentBox){
				//When a certain department is selected from combobox, 
				//show employees data in JTextArea
				Department d = (Department) event.getItem();
				employeeDataTa.setText("");
				for(Employee e : d.getEmployees()){
					employeeDataTa.append(e+":  $"+e.getSalary()+"\n");
				}
			}
		}
	}
	
	//JFrame for employee entry
	public class EmployeeFrame extends JFrame{
		
		JLabel employeeFirstNameLbl, employeeSurnameLbl, employeeAddressLbl, employeeGenderLbl, employeePayLevelLbl, employeeDepartmentLb;
		JTextField employeeFirstNameTf, employeeSurnameTf, employeeAddressTf;
		JRadioButton employeeMale, employeeFemale;
		JButton addEmployeeBtn, updateEmployeeBtn;
		JComboBox payLevelCombo, employeeDepartmentCombo;
		Employee e;
		eButtonHandler eButtonHandler = new eButtonHandler();
		String gender;
		
		public EmployeeFrame(int mode){
			super("Employee frame");
			employeeFirstNameLbl = new JLabel("First Name: ");
			employeeSurnameLbl = new JLabel("Surname: ");
			employeeGenderLbl = new JLabel("Gender: ");
			employeeAddressLbl = new JLabel("Address: ");
			employeePayLevelLbl = new JLabel("Pay Level: ");
			
			employeeFirstNameTf = new JTextField(20);
			employeeSurnameTf = new JTextField(20);
			employeeAddressTf = new JTextField(20);
			
			employeeMale = new JRadioButton("Male");
			employeeFemale = new JRadioButton("Female");
	        ButtonGroup buttonGroup = new ButtonGroup();
	        buttonGroup.add(employeeMale);
	        buttonGroup.add(employeeFemale);
	        
	        payLevelCombo = new JComboBox();
	        employeeDepartmentCombo = new JComboBox();
	        
	        addEmployeeBtn = new JButton("Add");
	        addEmployeeBtn.setSize(250, 30);
	        updateEmployeeBtn = new JButton("Update");
	        updateEmployeeBtn.setSize(250, 30);
	        
	        addEmployeeBtn.addActionListener(eButtonHandler);
	        updateEmployeeBtn.addActionListener(eButtonHandler);
	        
			setBounds(100,100,270, 300);
			setLayout(new FlowLayout());
			
			add(employeeFirstNameLbl);
			add(employeeFirstNameTf);
			
			add(employeeSurnameLbl);
			add(employeeSurnameTf);
			
			add(employeeAddressLbl);
			add(employeeAddressTf);
			
			//If in "new" mode then show gender selection
			if(mode != 1){
				add(employeeGenderLbl);
				add(employeeMale);
				add(employeeFemale);
			}
			
			add(employeeDepartmentCombo);
			
			add(employeePayLevelLbl);
			add(payLevelCombo);
			
			//Populate comboboxes
			for(int i=1; i<9; i++ ){
				payLevelCombo.addItem(new Integer(i));
			}
			
			for(Department d : departments){
				employeeDepartmentCombo.addItem(d);
			}
			
			//Show different buttons based on different mode
			if(mode == 0){
				add(addEmployeeBtn);
			}
			else if(mode == 1){
				add(updateEmployeeBtn);
			}
			
			//Populate employee data in components if in edit mode
			if(mode == 1){
				e = (Employee) employeesBox.getSelectedItem();
				employeeFirstNameTf.setText(e.getFirstName());
				employeeSurnameTf.setText(e.getSurname());
				employeeAddressTf.setText(e.getAddress());
				payLevelCombo.setSelectedIndex(e.getPayLevel()-1);
				int idx = 0;
				//Traverse through departments ArrayList to find employee's department and set it to combobox
				for(int i=0; i<departments.size(); i++){
					if(departments.get(i).toString().equals(e.getDepartment().toString())){
						idx = i;
					}
				}
				employeeDepartmentCombo.setSelectedIndex(idx);
			}
		}
		
		public void closeFrame(){
			setVisible(false);
			dispose();
		}
		
		//Employee radio button handler
	    private class RadioButtonHandler implements ActionListener {
	        public void actionPerformed( ActionEvent event ){
	        	//Change gender attributes if radiobutton is selected
	        	if(event.getSource() == employeeMale){
	        		gender = "M";
	        	}
	        	else if(event.getSource() == employeeFemale){
	        		gender = "F";
	        	}

	        }
	    }
	    
	    //Employee button handler
		private class eButtonHandler implements ActionListener{
			@Override
			public void actionPerformed(ActionEvent event) {
				Object o = event.getSource();
				if(o == addEmployeeBtn){
					String firstName = employeeFirstNameTf.getText();
					String surname = employeeSurnameTf.getText();
					String address = employeeAddressTf.getText();
					int payLevel = (Integer) payLevelCombo.getSelectedItem();
					
					if(firstName.length() < 1 || surname.length() < 1 || address.length() < 1){
						JOptionPane.showMessageDialog(getContentPane(), "Please fill in all fields !");
					}
					else{
						int id = hras.getEmployeeId();
						Employee emp;
						try {
							System.out.println("Current ID: "+id);
							emp = new Employee(firstName, surname, address, gender, (id+1), payLevel);
							System.out.println("Employee ID: "+emp.getId());
							hras.addEmployee(emp);
							hras.assignEmployeeToDepartment((Department) employeeDepartmentCombo.getSelectedItem(), emp);
							hras.setEmployeeId((id+1));
							JOptionPane.showMessageDialog(getContentPane(), "New employee added");
							
							employeesBox.removeAllItems();
							for(Integer i : employees.keySet()){
								employeesBox.addItem(employees.get(i));
							}
							closeFrame();
						} catch (SystemException e) {
							JOptionPane.showMessageDialog(getContentPane(), e.getMessage());
						}
					}
				}
				else if(o == updateEmployeeBtn){
					boolean isHead = false;
					e.setFirstName(employeeFirstNameTf.getText());
					e.setSurname(employeeSurnameTf.getText());
					e.setAddress(employeeAddressTf.getText());
					e.setPayLevel((Integer) payLevelCombo.getSelectedItem());
					try {
						e.setDepartment((Department) employeeDepartmentCombo.getSelectedItem());
					} catch (SystemException ex) {
						JOptionPane.showMessageDialog(getContentPane(), ex.getMessage());
					}
					
					JOptionPane.showMessageDialog(getContentPane(), "Updated details of employee: "+e.getId());
					closeFrame();
				}
			}
		}
	}
	
	//JFrame for department entry
	public class DepartmentFrame extends JFrame{
		JLabel departmentNameLbl, departmentLocationLbl;
		JTextField departmentNameTf, departmentLocationTf;
		JButton addDepartmentBtn;
		dButtonHandler dButtonHandler = new dButtonHandler();
		
		public DepartmentFrame(){
			super("Department frame");
			departmentNameLbl = new JLabel("Department Name: ");
			departmentLocationLbl = new JLabel("Department Location: ");
			
			departmentNameTf = new JTextField(20);
			departmentLocationTf = new JTextField(20);
			
			addDepartmentBtn = new JButton("Add");
			addDepartmentBtn.addActionListener(dButtonHandler);
			
			add(departmentNameLbl);
			add(departmentNameTf);
			add(departmentLocationLbl);
			add(departmentLocationTf);
			add(addDepartmentBtn);
			
			setBounds(100,100,270, 200);
			setLayout(new FlowLayout());
			
		}
		
		//Department button handler
		private class dButtonHandler implements ActionListener{
			@Override
			public void actionPerformed(ActionEvent event) {
				String name = departmentNameTf.getText();
				String location = departmentLocationTf.getText();
				if(name.length() < 1 || location.length() < 1){
					JOptionPane.showMessageDialog(getContentPane(), "Please fill in all fields !");
				}
				else{
					hras.addDepartment(new Department(name, location));
					departmentsBox.removeAllItems();
					for(Department d : hras.getAllDepartments()){
						departmentsBox.addItem(d);
					}
					assignDepartmentBox.removeAllItems();
					for(Department d : hras.getAllDepartments()){
						assignDepartmentBox.addItem(d);
					}
					//Close frame
					setVisible(false);
					dispose();
				}
			}
		}	
	}
}
